#include "init.h"

// 经测试，大约4800000为1秒，简化为4096为0.001秒
void delay(uint32_t ms)
{
  ms <<= 12;
  for (uint32_t i = 0; i < ms; i++)
  {
    asm volatile("nop\n");
  }
}

// 初始化usart1函数
void usart1Init()
{
  // 使能USART1的时钟
  RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
  // 使能GPIOA的时钟
  RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;

  // 配置USART1的引脚
  GPIOA->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_MODE9 | GPIO_CRH_CNF10 | GPIO_CRH_MODE10); // 清除原来的配置
  GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9;                                     // 将PA9配置为复用推挽输出模式
  GPIOA->CRH |= GPIO_CRH_CNF10_0;                                                     // 将PA10配置为浮空输入模式

  // 配置USART1的参数
  USART1->BRR = 0x0271;                      // 设置波特率，对应115200波特率
  USART1->CR1 = USART_CR1_RE | USART_CR1_TE; // 使能接收和发送功能
  USART1->CR1 |= USART_CR1_UE;               // 使能USART1模块

  // 清除USART1的标志位
  USART1->SR = 0;

}
void initClock(void)
{
  // 1. 使能HSE时钟
  SET_BIT(RCC->CR, RCC_CR_HSEON);

  // 2. 等待HSE就绪
  while (READ_BIT(RCC->CR, RCC_CR_HSERDY) == 0)
    ;

  // 3. 配置FLASH预取指和延迟
  SET_BIT(FLASH->ACR, FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_2);

  // 4. 配置HCLK = SYSCLK, 配置PCLK2 = HCLK, 配置PCLK1 = HCLK/2
  SET_BIT(RCC->CFGR, RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV1 | RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL9);

  // 5. 使能PLL
  SET_BIT(RCC->CR, RCC_CR_PLLON);

  // 6. 等待PLL就绪
  while (READ_BIT(RCC->CR, RCC_CR_PLLRDY) == 0)
    ;

  // 7. 选择PLL作为系统时钟源
  SET_BIT(RCC->CFGR, RCC_CFGR_SW_PLL);

  // 8. 等待PLL成为系统时钟源
  while (READ_BIT(RCC->CFGR, RCC_CFGR_SWS_1) == 0);
}

void init(void)
{
  // 初始化外部8M时钟源
  initClock();

  // 开启 GPIOA, GPIOC 时钟
  SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPAEN);
  SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPCEN);
  
  // 将PC13 LED背光引脚设置为输出模式
  CLEAR_BIT(GPIOC->CRH, (0xF << (5 * 4)));
  SET_BIT(GPIOC->CRH, (0x3 << (5 * 4)));

  // Wait 1uS so the pull-up settles...
  delay(72);

  // 将PC13引脚电平拉高
  WRITE_REG(GPIOC->BSRR, GPIO_BSRR_BS13);

#if DEBUG_ON == 1
  // 初始化USART1
  usart1Init();
#endif
}

#if DEBUG_ON == 1
#include <stdio.h>
// 重定向printf start ----------------------------------------------------------
// _write函数在syscalls.c中，使用__weak定义， 所以可以直接在其他文件中定义_write函數
__attribute__((weak)) int _write(int file, char *ptr, int len)
{
    for (int i = 0; i < len; i++)
    {
        USART1->DR = *ptr++;
        // 等待数据发送完毕
        while (!READ_BIT(USART1->SR, USART_SR_TXE)) ;
    }
    while (!READ_BIT(USART1->SR, USART_SR_TC));
    return len;
}
// 重定向printf end -------------------------------------------------------------
#endif
